import hashlib
import time

from django.conf import settings
from django.http import JsonResponse

from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
from rest_framework.response import Response

from XApiTestServer.models import UserInfo, UserToken
from XApiTestServer.utils.response import *

import logging


logger = logging.getLogger('XApiTestServer')

def login_normal(username, password):
    """
    Login the XApiTestServer platform using the registered account
    :param username: user name of the registered account
    :param password: password the registered password
    :return: True:successful, False: failed
    """
    user_obj = UserInfo.objects.filter(username__exact=username).first()

    if not user_obj:
        return Response(LOGIN_FAILED)

    # if not check_password(password, user.password):
    if not password == user_obj.password:
        return Response(LOGIN_FAILED)

    token = generate_token(username)

    logger.info('{username} 登录成功'.format(username=username))

    try:
        UserToken.objects.update_or_create(user=user_obj, defaults={"token": token})
    except ObjectDoesNotExist:
        return Response(SYSTEM_ERROR)
    else:
        LOGIN_SUCCESS["token"] = token
        LOGIN_SUCCESS["account"] = username

        return Response(LOGIN_SUCCESS)

'''
def login_ldap(username, password):
    """
    Login the XApiTestServer platform using the third system account
    :param username: user name of the third system
    :param password: password the third system
    :return: True:successful, False: failed
    """
    import ldap

    conn = ldap.initialize("ldap://xxxxx:389/")
    try:
        conn.simple_bind_s(username, password)
        return True
    except:
        traceback.print_exc()
        return False
'''

def create_ldap_user(account, password):
    ldap_user_info = {
        "username": account,
        "password": password,
        "email": 'ldap',
        "status": 1
    }

    try:
        if UserInfo.objects.filter(username=ldap_user_info.get('username')).count() > 0:
            return '已被其他使用，请联系管理员'

        UserInfo.objects.create(**ldap_user_info)
        logging.info('LDAP用户在本地添加成功: {ldap_user_info}'.format(ldap_user_info=ldap_user_info))
    except Exception as e:
        return 'LDAP用户添加异常，请重试'
    return 'ok'

def validate_ldap_user(account, password):
    """
    Validate the XApiTestServer platform using the third system account
    :param user: user name of the third system
    :param password: password the third system
    :return: True:successful, False: failed
    """
    user_obj = UserInfo.objects.filter(username__exact=account).first()

    if not user_obj:
        return Response(LOGIN_FAILED)

    token = generate_token(account)

    logger.info('{username} 登录成功'.format(username=account))

    try:
        UserToken.objects.update_or_create(user=user_obj, defaults={"token": token})
    except ObjectDoesNotExist:
        return Response(SYSTEM_ERROR)
    else:
        LOGIN_SUCCESS["token"] = token
        LOGIN_SUCCESS["account"] = account

        return Response(LOGIN_SUCCESS)

def generate_token(username):
    """
    generate token base account
    """
    timestamp = str(time.time())

    token = hashlib.md5(bytes(username, encoding='utf-8'))
    token.update(bytes(timestamp, encoding='utf-8'))

    return token.hexdigest()

def get_username(token):
    """
    get username by token
    """
    name = UserToken.objects.filter(token=token).values("user__username")
    return name[0]['user__username']


class Authenticator(BaseAuthentication):
    """
    账户鉴权认证 token
    """

    def authenticate(self, request):
        if request.path == '/api/login/' or request.path == '/api/register/':
        # if request.path == '/server/register/':
            pass
        else:
            # token key in header: HTTP_X_TOKEN
            token = request.META.get("HTTP_X_TOKEN", None)
            obj = UserToken.objects.filter(token=token).first()

            if not obj:
                raise exceptions.AuthenticationFailed(AUTH_USER_NOT_EXISTS)

            update_time = int(obj.update_time.timestamp())
            current_time = int(time.time())

            if current_time - update_time >= settings.INVALID_TIME:
                raise exceptions.AuthenticationFailed(AUTH_TOKEN_TIMEOUT)

            # valid update valid time
            obj.token = token
            obj.save()

            return obj.user, obj

    def authenticate_header(self, request):
        return 'Auth Failed'

